
interface MenuNode {

    "title": string;

    "depth": number;

    "id": string;

    "subItems": MenuNode[];
}

class HTMLContentMaker {

    public contentText: string;

    protected menuTree: MenuNode;

    protected doGenerate(menuTree: MenuNode): string {

        let html: string;

        if (menuTree.subItems) {

            if (menuTree.depth === 1) {

                html = `<h2>${this.contentText}</h2><ul>`;

            } else {

                html = `<p><a href="#${menuTree.id}">${menuTree.title}</a></p><ul>`;
            }

            for (let x of menuTree.subItems) {

                html += this.doGenerate(x);
            }

            html += "</ul>";

        } else {

            html = `<li><a href="#${menuTree.id}">${menuTree.title}</a></li>`;
        }

        return html;
    }

    public generate(): string {

        return this.doGenerate(this.menuTree);
    }

    public extract(html: string): boolean {

        let headlines: string[] = [];
        let matches: RegExpMatchArray;

        if (headlines = html.match(/<h(\d)\s+id\="([^"]+)"[^>]*>(.+)<\/h\d>/ig)) {

            let menuNodes: MenuNode[] = [];

            for (let line of headlines) {

                matches = line.match(/<h(\d)\s+id\="([^"]+)"[^>]*>(.+)<\/h\d>/i);

                menuNodes.push({
                    "title": matches[3],
                    "id": matches[2],
                    "depth": parseInt(matches[1]),
                    "subItems": []
                });

            }

            headlines = null;

            for (let index: number = 0; index < menuNodes.length; ++index) {

                let node: MenuNode = menuNodes[index];

                if (!this.menuTree) {

                    if (node.depth !== 1) {

                        return false;
                    }

                    this.menuTree = node;

                } else {

                    if (node.depth === 1) {

                        return false;
                    }

                    let noParentNode: boolean = true;

                    for (let i = index; i > 0; ) {

                        i--;

                        let pNode: MenuNode = menuNodes[i];

                        if (pNode.depth === node.depth - 1) {

                            pNode.subItems || (pNode.subItems = []);

                            pNode.subItems.push(node);

                            noParentNode = false;

                            break;
                        }
                    }

                    if (noParentNode) {

                        return false;
                    }

                }

            }

        }

        return true;
    }
}

export = HTMLContentMaker;
